//
//  BaseShelfQueue.swift
//  MySwiftObject
//
//  Created by anscen on 2022/2/22.
//  Copyright © 2022 wangws1990. All rights reserved.
//
import UIKit
import SQLite.Swift
private let CaseTable          = "CaseTable"

private let id             = Expression<String>("primaryId")
private let newIcon        = Expression<Int>("newIcon")
private let insertTime     = Expression<TimeInterval>("insertTime")//放入书架
private let updateTime     = Expression<TimeInterval>("updateTime")//最近阅读
private let topTime        = Expression<TimeInterval>("topTime")//置顶时间
private let lastChapter    = Expression<String?>("lastChapter")
private let book           = Expression<String?>("bookInfo")

class BaseShelfQueue {
    fileprivate lazy var table: Table? = {
        guard let db = dataBase.db else { return nil }
        let tables = Table(CaseTable)
        guard let _ = try? db.run(tables.create(ifNotExists: true, block: { (table) in
            //注意.autoincrement
            table.column(id,primaryKey: true)

            table.column(updateTime)
            table.column(insertTime)
            table.column(topTime)
            
            table.column(newIcon)
            table.column(book)
            table.column(lastChapter)
            
        })) else { return nil }
        let have = haveColumn("topTime")
        if !have{
            guard let _ = try? db.run(tables.addColumn(topTime,defaultValue:0)) else { return nil }
        }
        return tables
    }()
    private func selectCount(tableName :String,primaryId :String) ->Int{
        guard let db = dataBase.db else { return 0 }
        guard let tb = self.table else { return 0 }
        let alice = tb.filter(id == primaryId)
        guard let count = try? db.scalar(alice.count) else { return 0 }
        return count
    }
    private func haveColumn(_ column :String) -> Bool{
        return BaseConnection.haveColumn(CaseTable, column: column)
    }
    public func haveData(_ bookId :String) -> Bool{
        let count = selectCount(tableName: CaseTable, primaryId: bookId)
        return count  > 0 ? true : false
    }
}
extension BaseShelfQueue{
    public func insertData(bookId :String,
                                  bookInfo:String?,
                                  completion:@escaping ((_ success : Bool) -> ())){
        guard let db = dataBase.db else { return completion(false) }
        guard let tb = self.table else { return completion(false) }
        let count = haveData(bookId)
        let time = Date().timeIntervalSince1970
        if !count{
            let insertdata = tb.insert(id <- bookId,
                                       insertTime <- time,
                                       updateTime <- 0,
                                       topTime <- 0,
                                       newIcon <- 0,
                                       lastChapter <- "",
                                       book <- bookInfo ?? "")
            guard let _ = try? db.run(insertdata) else { return completion(false) }
            completion(true)
        }
    }
    public func updateBook(bookId :String, bookInfo:String,completion:@escaping ((_ success : Bool) -> ())){
        if haveData(bookId){
            guard let tb = self.table else { return completion(false) }
            let time = Date().timeIntervalSince1970
            let run = tb.filter(bookId == id)
            let update = run.update(id <- bookId,book <- bookInfo,updateTime <- time)
            runUpdate(update, completion: completion)
        }else{
            insertData(bookId: bookId, bookInfo: bookInfo, completion: completion)
        }
    }
    public func updateNew(bookId :String,new :Int,lastChap :String? = nil,completion:@escaping ((_ success : Bool) -> ())){
        if haveData(bookId){
            guard let tb = self.table else { return completion(false) }
            let time = Date().timeIntervalSince1970
            let run = tb.filter(bookId == id)
            if let chap = lastChap{
                let update = run.update(id <- bookId,updateTime <- time,newIcon <- new,lastChapter <- chap)
                runUpdate(update, completion: completion)
            }else{
                let update = run.update(id <- bookId,updateTime <- time,newIcon <- new)
                runUpdate(update, completion: completion)
            }
        }
    }
    public func updateTop(bookId :String,cancle :Bool,completion:@escaping ((_ success : Bool) -> ())){
        if haveData(bookId){
            guard let tb = self.table else { return completion(false) }
            let time = cancle ? 0 : Date().timeIntervalSince1970
            let run = tb.filter(bookId == id)
            let update = run.update(id <- bookId,topTime <- time)
            runUpdate(update, completion: completion)
        }
    }
    public func updateTimes(bookId :String,completion:@escaping ((_ success : Bool) -> ())){
        if haveData(bookId){
            guard let tb = self.table else { return completion(false) }
            let time = Date().timeIntervalSince1970
            let run = tb.filter(bookId == id)
            let update = run.update(id <- bookId,updateTime <- time)
            runUpdate(update, completion: completion)
        }
    }
    public func getData(page : Int,size : Int = 20,completion:@escaping ((_ datas : [GKBook]) ->())){
        guard let db = dataBase.db else { return completion([]) }
        guard let tb = self.table else { return completion([]) }
        let order = tb.order(insertTime.desc).limit(size, offset: (page - 1) * size)
        guard let datas : AnySequence<Row> = try? db.prepare(order) else {
            return completion([])
        }
        decodeData(listData: datas,completion: completion)
    }
    public func getData(completion:@escaping ((_ datas : [GKBook]) ->())){
        guard let db = dataBase.db else { return completion([]) }
        guard let tb = self.table else { return completion([]) }
        guard let datas : AnySequence<Row> = try? db.prepare(tb) else {
            return completion([])
        }
        decodeData(listData: datas,completion: completion)
    }
    public func searchData(bookId :String,completion:@escaping ((_ book : GKBook?) -> ())){
        guard let db = dataBase.db else { return completion(nil) }
        guard let table = self.table else { return completion(nil) }
        let alice = table.filter(id == bookId)
        
        guard let datas : AnySequence<Row> = try? db.prepare(alice) else {
            return completion(nil)
        }
        let objc = datas.first { row in
            return String(row[id]).count > 0
        }
        guard let row = objc else {
            return completion(nil)
        }
        let his = decode(objc:row)
        completion(his)
    }
    public func deleteData(bookId :String,completion:@escaping ((_ success : Bool) -> ())){
        guard let db = dataBase.db else { return completion(false) }
        guard let tb = self.table else { return completion(false) }
        let alice = tb.filter(id == bookId)
        guard let _ = try? db.run(alice.delete()) else { return completion(false) }
        completion(true)
    }
    private func decodeData(listData : AnySequence<Row>,completion:@escaping ((_ datas : [GKBook]) ->())){
        DispatchQueue.global().async {
            var content : [GKBook] = []
            listData.forEach { (objc) in
                if let model = self.decode(objc: objc){
                    content.append(model)
                }
            }
            DispatchQueue.main.async {
                completion(content)
            }
        }
    }
    private func decode(objc : Row) -> GKBook?{
        var model =  GKBook()
        if let json = try? objc.get(book) {
            let bookJson = JSON(parseJSON:json)
            if let item = GKBook.deserialize(from: bookJson.rawString()){
                model = item
            }
        }
        if let bookId = try? objc.get(id) {
            model.bookId = bookId
        }
        if let time = try? objc.get(insertTime){
            model.insertTime =  TimeInterval(time)
        }
        if let time = try? objc.get(updateTime){
            model.updateTime =  TimeInterval(time)
        }
        if let time = try? objc.get(topTime){
            model.topTime =  TimeInterval(time)
        }
        if let new = try? objc.get(newIcon){
            model.new =  new == 1 ? true : false
        }
        if let last = try? objc.get(lastChapter){
            model.lastChapter = last
        }
        return model
    }
    fileprivate func runUpdate(_ task :Update,completion:@escaping ((_ success : Bool) -> ())){
        guard let db = dataBase.db else { return completion(false) }
        guard let _ = try? db.run(task) else { return completion(false) }
        completion(true)
    }
}
